package com.gingko.duominuo.utils

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import java.io.Serializable

inline fun <reified T : Activity> Activity.startKtxActivity(
        flags: Int? = null,
        extra: Bundle? = null,
        value: Pair<String, Any>? = null,
        values: Collection<Pair<String, Any>?>? = null
) {

    val list = ArrayList<Pair<String, Any>?>()
    value?.let { list.add(it) }
    values?.let { list.addAll(it) }
    startActivity(getIntent<T>(flags, extra, list))
}

inline fun <reified T : Activity> Fragment.startKtxActivity(
        flags: Int? = null,
        extra: Bundle? = null,
        value: Pair<String, Any>? = null,
        values: Collection<Pair<String, Any>?>? = null
) = activity?.let {
    val list = ArrayList<Pair<String, Any>?>()
    value?.let { v -> list.add(v) }
    values?.let { v -> list.addAll(v) }
    startActivity(it.getIntent<T>(flags, extra, list))
}

inline fun <reified T : Activity> Context.startKtxActivity(
        flags: Int? = null,
        extra: Bundle? = null,
        value: Pair<String, Any>? = null,
        values: Collection<Pair<String, Any>?>? = null
) {
    val list = ArrayList<Pair<String, Any>?>()
    value?.let { v -> list.add(v) }
    values?.let { v -> list.addAll(v) }
    startActivity(getIntent<T>(flags, extra, list))
}

inline fun <reified T : Activity> Activity.startKtxActivityForResult(
        requestCode: Int,
        flags: Int? = null,
        extra: Bundle? = null,
        value: Pair<String, Any>? = null,
        values: Collection<Pair<String, Any>?>? = null
) {
    val list = ArrayList<Pair<String, Any>?>()
    value?.let { list.add(it) }
    values?.let { list.addAll(it) }
    startActivityForResult(getIntent<T>(flags, extra, list), requestCode)
}

inline fun <reified T : Activity> Fragment.startKtxActivityForResult(
        requestCode: Int,
        flags: Int? = null,
        extra: Bundle? = null,
        value: Pair<String, Any>? = null,
        values: Collection<Pair<String, Any>?>? = null
) = activity?.let {
    val list = ArrayList<Pair<String, Any>?>()
    value?.let { list.add(it) }
    values?.let { list.addAll(it) }
    startActivityForResult(activity?.getIntent<T>(flags, extra, list), requestCode)
}

inline fun <reified T : Context> Context.getIntent(
        flags: Int? = null,
        extra: Bundle? = null,
        pairs: List<Pair<String, Any>?>? = null
): Intent = Intent(this, T::class.java).apply {
    flags?.let { setFlags(flags) }
    extra?.let { putExtras(extra) }
    pairs?.let {
        for (pair in pairs)
            pair?.let {
                val name = pair.first
                when (val value = pair.second) {
                    is Int -> putExtra(name, value)
                    is Byte -> putExtra(name, value)
                    is Char -> putExtra(name, value)
                    is Short -> putExtra(name, value)
                    is Boolean -> putExtra(name, value)
                    is Long -> putExtra(name, value)
                    is Float -> putExtra(name, value)
                    is Double -> putExtra(name, value)
                    is String -> putExtra(name, value)
                    is CharSequence -> putExtra(name, value)
                    is Parcelable -> putExtra(name, value)
                    is Array<*> -> putExtra(name, value)
                    is ArrayList<*> -> putExtra(name, value)
                    is Serializable -> putExtra(name, value)
                    is BooleanArray -> putExtra(name, value)
                    is ByteArray -> putExtra(name, value)
                    is ShortArray -> putExtra(name, value)
                    is CharArray -> putExtra(name, value)
                    is IntArray -> putExtra(name, value)
                    is LongArray -> putExtra(name, value)
                    is FloatArray -> putExtra(name, value)
                    is DoubleArray -> putExtra(name, value)
                    is Bundle -> putExtra(name, value)
                    is Intent -> putExtra(name, value)
                    else -> {
                    }
                }
            }
    }
}

inline fun <reified T : Fragment> FragmentActivity.showFragment(
        replaceViewId: Int, init: (T).() -> Unit = {}
): T {
    val sfm = supportFragmentManager
    val transaction = sfm.beginTransaction()
    var fragment = sfm.findFragmentByTag(T::class.java.name)
    if (fragment == null) {
        fragment = T::class.java.newInstance()
        transaction.add(replaceViewId, fragment, T::class.java.name)
    }
    sfm.fragments.filter { it != fragment }.forEach { transaction.hide(it) }
    transaction.show(fragment!!)
    transaction.commitAllowingStateLoss()
    sfm.executePendingTransactions()
    init(fragment as T)
    return fragment
}

inline fun <reified T : Fragment> FragmentActivity.getFragment(
        init: (T)?.() -> Unit = {}
): T? {
    val fragment = supportFragmentManager.findFragmentByTag(T::class.java.name)
    init(fragment as T?)
    return fragment
}

inline fun <reified T : Fragment> Fragment.showFragment(
        replaceViewId: Int, init: (T).() -> Unit = {}
): T {
    val sfm = childFragmentManager
    val transaction = sfm.beginTransaction()
    var fragment = sfm.findFragmentByTag(T::class.java.name)
    if (fragment == null) {
        fragment = T::class.java.newInstance()
        transaction.add(replaceViewId, fragment, T::class.java.name)
    }
    sfm.fragments.filter { it != fragment }.forEach { transaction.hide(it) }
    transaction.show(fragment!!)
    transaction.commitAllowingStateLoss()
    sfm.executePendingTransactions()
    init(fragment as T)
    return fragment
}

inline fun <reified T : Fragment> Fragment.getFragment(
        init: (T)?.() -> Unit = {}
): T? {
    val fragment = childFragmentManager.findFragmentByTag(T::class.java.name)
    init(fragment as T?)
    return fragment
}


inline fun <reified T : Fragment> newInstance(context: Context, bundle: Bundle? = bundleOf()): T = T::class.java.newInstance().apply {
    arguments = bundle
}